﻿// Inner Fire 游戏引擎库
// GameInput - 输入管理器
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 所属层级：应用(4)
// 用于游戏的输入管理
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-04-26

#pragma once
#include <EASTL/array.h>
#include <EASTL/vector.h>
// 从 Windows 头文件中排除极少使用的内容
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include <functional>
#include <hidsdi.h>
#include <hidusage.h>

namespace ifire::game {

enum InputButtonEvent { DOWN = 0, UP = 1 };

/// <summary>
/// 用于印射游戏手柄
/// </summary>
enum GamepadButton {
  A = 0,
  B = 1,
  X = 2,
  Y = 3,

  // 肩键
  LeftBumper = 4,  // LB/L1
  RightBumper = 5, // RB/R1

  // 功能键
  Back = 6,  // Select/Share
  Start = 7, // Start/Options

  // 摇杆按下
  LeftStick = 8,  // LS
  RightStick = 9, // RS

  // 方向键 (D-Pad)
  DPadUp = 10,
  DPadDown = 11,
  DPadLeft = 12,
  DPadRight = 13,

  // 其他按钮
  Guide = 14,    // Xbox按钮/PS按钮
  Touchpad = 15, // PS触摸板按钮
};

/// <summary>
/// 用于保存每一帧的Button的状态。
/// 在每一帧结束的时候，就会重置为原来的状态。然后每一帧之前，随RAW_INPUT消息处理
/// </summary>
struct InputButtonState {
  // 在这一帧的间隔中，是否被按下
  bool is_pushed;
  // 在这一帧的间隔中，是否被释放。要达到这个为TRUE，必须这一帧之中先is_pushed为TRUE，然后再被设置为False。
  bool is_released;
  // 用于保存上一帧的情况
  bool last_pushed;
  bool last_released;

  InputButtonState()
      : is_pushed(false)
      , is_released(false)
      , last_pushed(false)
      , last_released(false) {}

  void OnFrameEnd() {
    last_pushed = is_pushed;
    last_released = is_released;
    is_pushed = false;
    is_released = false;
  };
};

class GameManager;

class GameInput {
public:
  GameInput(GameManager* gm);
  GameInput(const GameInput& lhs) = delete;
  GameInput& operator=(const GameInput& lhs) = delete;
  ~GameInput();

  // 初始化Raw Input设备
  bool Initialize(HWND hWnd);

  // 处理WM_INPUT消息
  void ProcessInputMessage(LPARAM lParam);
  // 处理游戏摇杆
  void OnJoystick(RAWINPUT* raw);

  // 处理摇杆方向
  void OnJoystickAxis(USAGE usage, HIDP_VALUE_CAPS& cap, ULONG value);
  // 处理摇杆按钮
  bool IsGamepadButtonDown(int button) const;
  // 获取当前帧鼠标移动增量
  void GetMouseDelta(int& dx, int& dy) const;

  // 获取当前帧（左）摇杆状态
  void GetLeftStick(float& x, float& y) const;
  // 获取当前帧（右）摇杆状态
  void GetRightStick(float& rx, float& ry) const;

  // 获得死区
  float GetDeadZone() const { return dead_zone_; }
  void SetDeadZone(float value) { dead_zone_ = value; }

  // 重置累计的鼠标移动量（通常在每帧结束时调用）
  void ResetMouseDelta();

  // 检查鼠标按钮状态
  bool IsMouseButtonDown(int button) const;

  // 锁定/解锁鼠标到窗口中心（FPS模式）
  void SetMouseLock(bool locked) const;

  // 调用事件
  void OnButtonEvents(
      const std::function<void(int, InputButtonEvent)>& event_handler);

  // 清空状态
  void OnFrameEnd();

private:
  GameManager* gm_;
  HWND hwnd_ = nullptr;
  int deltaX_ = 0;
  int deltaY_ = 0;
  bool buttons_[5] = {false}; // 0:左键 1:右键 2:中键 3:X1 4:X2
  std::array<BYTE, 1024> rawInputBuffer_; // 预分配足够大的缓冲区
  float left_stick_x_ = 0.0f, left_stick_y_ = 0.0f; // 左摇杆 - 角色移动
  float right_stick_x_ = 0.0f, right_stick_y_ = 0.0f; // 右摇杆 - 视野控制
  float dead_zone_ = 0.2f;                            // 死区

  // 当前帧RAWINPUT采集的按钮状态
  eastl::array<bool, 16> gamepad_buttons_;
  eastl::array<InputButtonState, 16> gamepad_states_;
};

} // namespace ifire::game